/**
 * 
 */
package com.google.code.cisx.wfe.model;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import com.google.code.cisx.wfe.api.WorkflowException;
import com.google.code.cisx.wfe.events.TypedEvent;
import com.google.code.cisx.wfe.events.TypedEventListener;

/**
 * @author <a href='mailto:rthakur@bravurasolutions.com'>Rahul Thakur</a>
 * @since 1.0
 * @version $Id$
 */
public abstract class AbstractCase<D> extends AbstractPetriNetEntity<D>
        implements Case<D> {

    /**
     * Transitions that are member of this workflow/case.
     */
    private List<Transition<?>> transitions = new ArrayList<Transition<?>>();

    /**
     * Places that are a member of this workflow/case.
     */
    private List<Place<?>> places = new ArrayList<Place<?>>();

    /**
     * InputArcs that are a member of this workflow/case.
     */
    private List<InputArc<?>> inputArcs = new ArrayList<InputArc<?>>();

    /**
     * OutputArcs that are a member of this workflow/case.
     */
    private List<OutputArc<?>> outputArcs = new ArrayList<OutputArc<?>>();

    /**
     * All members of this workflow/case.
     */
    @SuppressWarnings("unchecked")
    private List allEntities;

    /**
     * @param label
     */
    public AbstractCase(String label) {
        super(label);
    }

    /**
     * Create a Case with specified label and with specified {@link Place}s,
     * {@link Transition}s, {@link InputArc}s and {@link OutputArc}s.
     * <p>
     * After calling this constructor there is not need to call
     * {@link #register(PetriNetEntity)}.
     * 
     * @param transitions
     * @param places
     * @param inputArcs
     * @param outputArcs
     */
    public AbstractCase(String label, List<Transition<?>> transitions,
            List<Place<?>> places, List<InputArc<?>> inputArcs,
            List<OutputArc<?>> outputArcs) {
        super(label);
        this.transitions = transitions;
        this.places = places;
        this.inputArcs = inputArcs;
        this.outputArcs = outputArcs;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.google.code.cisx.wfe.model.Case#addEventListener(com.google.code.
     * cisx.wfe.events.TypedEventListener)
     */
    @Override
    public <E extends TypedEvent<? extends PetriNetEntity<?>>, L extends TypedEventListener<E>> void addEventListener(
            L listener) {
        // TODO Auto-generated method stub

    }

    /*
     * (non-Javadoc)
     * 
     * @see com.google.code.cisx.wfe.model.Case#getInitialPlace()
     */
    @Override
    public Place<?> getSource() {
        return this.places.get(0);
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.google.code.cisx.wfe.model.Case#getSink()
     */
    @Override
    public Place<?> getSink() {
        return this.places.get(this.places.size() - 1);
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.google.code.cisx.wfe.model.Case#getInitialTransition()
     */
    @Override
    public Transition<?> getInitialTransition() {
        if (null != this.transitions && this.transitions.size() > 0)
            return this.transitions.get(0);
        return null;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.google.code.cisx.wfe.model.Case#getInputArcs()
     */
    @Override
    public List<InputArc<?>> getInputArcs() {
        return this.inputArcs;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.google.code.cisx.wfe.model.Case#getOutputArcs()
     */
    @Override
    public List<OutputArc<?>> getOutputArcs() {
        return this.outputArcs;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.google.code.cisx.wfe.model.Case#getPetriNetEntities()
     */
    @SuppressWarnings("unchecked")
    @Override
    public List<? extends PetriNetEntity<?>> getPetriNetEntities() {
        if (null == this.allEntities || this.allEntities.size() == 0) {
            allEntities = new ArrayList();
            allEntities.addAll(this.places);
            allEntities.addAll(this.transitions);
            allEntities.addAll(this.inputArcs);
            allEntities.addAll(this.outputArcs);
        }
        return this.allEntities;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.google.code.cisx.wfe.model.Case#getPlaces()
     */
    @Override
    public List<Place<?>> getPlaces() {
        return this.places;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.google.code.cisx.wfe.model.Case#getTransitions()
     */
    @Override
    public List<Transition<?>> getTransitions() {
        return this.transitions;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.google.code.cisx.wfe.model.Case#query(java.lang.Class,
     * java.util.UUID)
     */
    @Override
    public <T extends PetriNetEntity<?>> T query(Class<T> klass, UUID uuid)
            throws WorkflowException {
        return null;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.google.code.cisx.wfe.model.Case#query(java.lang.Class,
     * java.lang.String)
     */
    @Override
    public <T extends PetriNetEntity<?>> T query(Class<T> klass, String label)
            throws WorkflowException {
        return null;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.google.code.cisx.wfe.model.Case#register(com.google.code.cisx.wfe
     * .model.PetriNetEntity)
     */
    @Override
    public <T extends PetriNetEntity<?>> Case<D> register(T entity) {
        if (entity instanceof Place<?>)
            this.places.add((Place<?>) entity);
        else if (entity instanceof Transition<?>)
            this.transitions.add((Transition<?>) entity);
        else if (entity instanceof InputArc<?>)
            this.inputArcs.add((InputArc<?>) entity);
        else if (entity instanceof OutputArc<?>)
            this.outputArcs.add((OutputArc<?>) entity);
        else {
            // Unknown Petri-Net entity
        }

        return this;
    }

}
